"""

.. module:: showspacestask
.. moduleauthor:: @author: 

The purpose of this module is ... 
   
.. seealso:: modules :mod:`<module>`

*Constants*:
.. data:: constant_1
        
    constant_1 is used for ......
        
.. data:: constant_2
        
    constant_2 is used for ......
"""

# Imports
#
import logging

from runtime.task import Task
from datastore.resource import Resource
from datastore.uri import Uri

# from services.httpserver import *       # FIXME: not sure why I need this

# Constants
#

# Classes
#

class ShowSpacesTask(Task):
    """This class is a daemon task. It processes requests from httpserver::RequestHandler
    and return Spaces resources.

    *Usage examples*::

        example code

    *Common Arguments for Class methods*:
        <arguments>
    
    *Audience*:
        <audience>
    
    *Constants*:
        .. data:: constant_1
        
            constant_1 is used for ......
        
        .. data:: constant_2
        
            constant_2 is used for ......
    """
    
    # Class constants
    #
    ALL_NAMESPACES = {
            Resource.BINDING_NS_NAME_YARRA : Resource.BINDING_NS_URI_YARRA,
            Resource.BINDING_NS_NAME_DUBLINCORE : Resource.BINDING_NS_URI_DUBLINCORE,
            Resource.BINDING_NS_NAME_DATASTORE : Resource.BINDING_NS_URI_DATASTORE,
            Resource.BINDING_NS_NAME_PACKAGE : Resource.BINDING_NS_URI_PACKAGE,
            Resource.BINDING_NS_NAME_RUNTIME : Resource.BINDING_NS_URI_RUNTIME,
            Resource.BINDING_NS_NAME_CONFIG : Resource.BINDING_NS_URI_CONFIG,
            Resource.BINDING_NS_NAME_TASK : Resource.BINDING_NS_URI_TASK,
            Resource.BINDING_NS_NAME_SERVICES : Resource.BINDING_NS_URI_SERVICES,
            Resource.BINDING_NS_NAME_LOCALHOST : Resource.BINDING_NS_URI_LOCALHOST,
            Resource.BINDING_NS_NAME_HTMLTEMPLATE : Resource.BINDING_NS_URI_HTMLTEMPLATE,
            Resource.BINDING_NS_NAME_TIME : Resource.BINDING_NS_URI_TIME,
            Resource.BINDING_NS_NAME_FILES : Resource.BINDING_NS_URI_FILES,
            Resource.BINDING_NS_NAME_HTTPCLIENT : Resource.BINDING_NS_URI_HTTPCLIENT,
            Resource.BINDING_NS_NAME_SITE : Resource.BINDING_NS_URI_SITE
            }
    
    def __init__(self, ds, spaces, task_uri, task_def_rs):
        # <purpose>
        #
        # Parameters:
        #     ds : datastore.database.DataStore
        #     spaces : runtime.spaces.Spaces - Reference to spaces
        #     task_uri : String - the uri for this task. The root uri will most
        #                likely be the 'binding' uri for this task.
        #     task_def_rs : datastore.resource.Resource - Task definition resource.
        #
        
        Task.__init__(self, ds, spaces, task_uri, task_def_rs)
        
        self.logger = logging.getLogger('yarra.services.httptask.ShowSpacesTask')
        self.logger.log(logging.DEBUG, "ds (%s), spaces (%s), task_uri (%s), task_def_rs (%s)" % (ds, spaces, task_uri, task_def_rs.pretty_print()))
        
    def cb_start(self, method, uri, new_uri, result, context, **kwargs):
        """This function is called when the task starts. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        
        self.logger.log(logging.DEBUG, "***************** uri (%s), new_uri (%s)" % (uri, new_uri))
        
        # All 'put' messages to this task are interpreted as requests for Spaces Resources.
        #
        self.spaces_context.process(uri.add("listen"), put='put_resource')
        
    def cb_stop(self, method, uri, res, result, context, **kwargs):
        """This function will stop any listeners still running.
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param res: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        
        self.logger.log(logging.DEBUG, "method (%s), uri (%s)" % (method, uri))
    
    def put_resource(self, method, uri, res, result, context, **kwargs):
        """This function retrieves the Spaces Resource at the Uri in the Resource
        at the argument Uri.
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param res: Resource
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        
        self.logger.log(logging.DEBUG, "uri (%s), res (%s), result (%s)" % (str(uri), res, result))
        
        requested_uri = res.get_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_REQUEST_URI)
        output_rs = Resource()
        
        # remove leading '/', if any...
        #
        if (requested_uri.match('/')):
            requested_uri = Uri(str(requested_uri)[1:], ShowSpacesTask.ALL_NAMESPACES)
        
        if (len(str(requested_uri)) == 0):
            # return namespaces
            #
            output_rs.set_var('namespaces_dict', self.spaces.get_bindings())
        else:
            # see if spaces has the requested Uri
            #
            spaces_rs = self.spaces_context.get(requested_uri)
            if (spaces_rs is not None):
                output_rs.set_var('resource_dict', spaces_rs.get_vars())
            else:
                # return all Uris, if any, under the requested Uri.
                #
                uri_list = self.spaces_context.dump(requested_uri)
                output_rs.set_var('resources_list', uri_list)
        
        # Note: The convention for returning Resources from a server task (like 
        #       this) to clients is:
        #
        #       1. create a Uri based on the server task's Uri, appended with the
        #          parts:
        #          - "requests"
        #          - <uuid>
        #          - "response"
        #       2. put() the output Resource to Spaces using the Uri.
        #       3. return a copy of the Uri to the client, with only the first 2 
        #          parts, for them to request the result Resource from Spaces.
        #          The client will get_wait() on:
        #
        #          <response_uri>.add("response")
        # 
        #       A consequence of this is that the server task CANNOT process 
        #       requests sent to "<task_uri>.collection(True)" because they will
        #       process the response Resources. (Actually the server task will 
        #       block on Spaces.put() because the same task is waiting on the Uri.)
        #
        response_uri = self.spaces_context.uri(self.task_uri).add("requests").add(str(self.spaces_context.uuid()))
        self.spaces_context.put(response_uri.add("response"), output_rs)
        return (True, response_uri.uri_copy())